<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/blog/images/logo.svg" color="#222">
  <meta name="baidu-site-verification" content="code-ia4sE56m4l">

<link rel="stylesheet" href="/blog/css/main.css">


<link rel="stylesheet" href="/blog/lib/font-awesome/css/all.min.css">
  
  <link rel="stylesheet" href="/blog/lib/animate-css/animate.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css">

<script class="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"tangmonk-meat.gitee.io","root":"/blog/","scheme":"Muse","version":"8.0.0-rc.4","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":true,"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":true,"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":"valine","storage":true,"lazyload":true,"nav":null,"activeClass":"valine"},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"path":"search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}};
  </script>

  <meta name="description" content="1 基本概念1.1 JDBCJDBC 的全称是Java数据库连接(Java Database Connectivity，简称JDBC),是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口。 提供了诸如查询和更新数据库中数据的方法,JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。">
<meta property="og:type" content="article">
<meta property="og:title" content="SpringBoot2.x整合JDBC与数据源配置原理解析">
<meta property="og:url" content="https://tangmonk-meat.gitee.io/blog/2021/03/19/springboot2.x%E6%95%B4%E5%90%88JDBC%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%BA%90%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/index.html">
<meta property="og:site_name" content="唐僧肉BLOG">
<meta property="og:description" content="1 基本概念1.1 JDBCJDBC 的全称是Java数据库连接(Java Database Connectivity，简称JDBC),是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口。 提供了诸如查询和更新数据库中数据的方法,JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9zMS5heDF4LmNvbS8yMDIwLzA4LzA4L2E0WmJNOC5wbmc?x-oss-process=image/format,png">
<meta property="article:published_time" content="2021-03-19T13:16:54.938Z">
<meta property="article:modified_time" content="2020-09-23T02:28:36.258Z">
<meta property="article:author" content="TANGMONK-MEAT">
<meta property="article:tag" content="SpringBoot">
<meta property="article:tag" content="Spring">
<meta property="article:tag" content="jdbc">
<meta property="article:tag" content="源码">
<meta property="article:tag" content="HikariCP">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9zMS5heDF4LmNvbS8yMDIwLzA4LzA4L2E0WmJNOC5wbmc?x-oss-process=image/format,png">

<link rel="canonical" href="https://tangmonk-meat.gitee.io/blog/2021/03/19/springboot2.x%E6%95%B4%E5%90%88JDBC%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%BA%90%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/">


<script class="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>SpringBoot2.x整合JDBC与数据源配置原理解析 | 唐僧肉BLOG</title>
  






  <noscript>
  <style>
  body { margin-top: 2rem; }

  .use-motion .menu-item,
  .use-motion .sidebar,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header {
    visibility: visible;
  }

  .use-motion .header,
  .use-motion .site-brand-container .toggle,
  .use-motion .footer { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle,
  .use-motion .custom-logo-image {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line {
    transform: scaleX(1);
  }

  .search-pop-overlay, .sidebar-nav { display: none; }
  .sidebar-panel { display: block; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <main class="main">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader">
        <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/blog/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">唐僧肉BLOG</h1>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">记录生活中的点点滴滴</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/blog/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/blog/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/blog/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签<span class="badge">44</span></a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/blog/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类<span class="badge">17</span></a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/blog/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档<span class="badge">38</span></a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <section class="post-toc-wrap sidebar-panel">
          <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#1-%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5"><span class="nav-number">1.</span> <span class="nav-text">1 基本概念</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-1-JDBC"><span class="nav-number">1.1.</span> <span class="nav-text">1.1 JDBC</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-2-%E6%95%B0%E6%8D%AE%E6%BA%90"><span class="nav-number">1.2.</span> <span class="nav-text">1.2 数据源</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#2-%E6%95%B4%E5%90%88%E6%AD%A5%E9%AA%A4"><span class="nav-number">2.</span> <span class="nav-text">2 整合步骤</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#2-1-%E5%BC%95%E5%85%A5JDBC%E7%9A%84Starter"><span class="nav-number">2.1.</span> <span class="nav-text">2.1 引入JDBC的Starter</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-2-%E5%BC%95%E5%85%A5%E8%BF%9E%E6%8E%A5%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E9%A9%B1%E5%8A%A8"><span class="nav-number">2.2.</span> <span class="nav-text">2.2 引入连接数据库的驱动</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-3-%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E6%BA%90-%E9%BB%98%E8%AE%A4HikariCP"><span class="nav-number">2.3.</span> <span class="nav-text">2.3 配置数据源(默认HikariCP)</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3-1-%E6%95%B0%E6%8D%AE%E6%BA%90%E5%AE%8C%E6%95%B4%E9%85%8D%E7%BD%AE%E9%A1%B9%E8%A1%A8"><span class="nav-number">2.3.1.</span> <span class="nav-text">2.3.1 数据源完整配置项表</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3-2-%E4%BD%BF%E7%94%A8%E5%85%B6%E4%BB%96%E6%95%B0%E6%8D%AE%E6%BA%90%EF%BC%88Druid%EF%BC%89"><span class="nav-number">2.3.2.</span> <span class="nav-text">2.3.2 使用其他数据源（Druid）</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%EF%BC%881%EF%BC%89%E6%8E%92%E9%99%A4%E9%BB%98%E8%AE%A4%E6%95%B0%E6%8D%AE%E6%BA%90"><span class="nav-number">2.3.2.1.</span> <span class="nav-text">（1）排除默认数据源</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%EF%BC%882%EF%BC%89%E5%BC%95%E7%94%A8-%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4%E7%9A%84Druid%E6%95%B0%E6%8D%AE%E6%BA%90"><span class="nav-number">2.3.2.2.</span> <span class="nav-text">（2）引用　阿里巴巴的Druid数据源</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%EF%BC%883%EF%BC%89%E9%85%8D%E7%BD%AEDruid%E6%95%B0%E6%8D%AE%E6%BA%90"><span class="nav-number">2.3.2.3.</span> <span class="nav-text">（3）配置Druid数据源</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#3-%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%EF%BC%88%E4%BB%A5hikari%E4%B8%BA%E4%BE%8B%EF%BC%89"><span class="nav-number">3.</span> <span class="nav-text">3 数据源的自动配置原理（以hikari为例）</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#3-1-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E5%8F%8A%E5%85%B6%E7%BB%93%E6%9E%9C"><span class="nav-number">3.1.</span> <span class="nav-text">3.1 单元测试及其结果</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-2-%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90"><span class="nav-number">3.2.</span> <span class="nav-text">3.2 原理解析</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-1-%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E5%AF%BC%E5%85%A5%E9%85%8D%E7%BD%AE"><span class="nav-number">3.2.1.</span> <span class="nav-text">3.2.1 数据源的导入配置</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%EF%BC%881%EF%BC%89hikari%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86"><span class="nav-number">3.2.1.1.</span> <span class="nav-text">（1）hikari的数据源的配置原理</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%EF%BC%882%EF%BC%89-%E6%95%B0%E6%8D%AE%E6%BA%90%E6%9E%84%E5%BB%BA%E5%99%A8%EF%BC%88DataSourceBuilder%EF%BC%89"><span class="nav-number">3.2.1.2.</span> <span class="nav-text">（2） 数据源构建器（DataSourceBuilder）</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%EF%BC%883%EF%BC%89-hikari%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE"><span class="nav-number">3.2.1.3.</span> <span class="nav-text">（3） hikari数据源的自动配置</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%EF%BC%884%EF%BC%89%E4%BD%BF%E7%94%A8%E5%85%B6%E4%BB%96%E6%95%B0%E6%8D%AE%E6%BA%90"><span class="nav-number">3.2.1.4.</span> <span class="nav-text">（4）使用其他数据源</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%EF%BC%885%EF%BC%89%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96"><span class="nav-number">3.2.1.5.</span> <span class="nav-text">（5）数据源的初始化</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#1-gt-DataSourceInitializerInvoke%E7%B1%BB"><span class="nav-number">3.2.1.5.1.</span> <span class="nav-text">1&gt; DataSourceInitializerInvoke类</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-gt-DataSourceInitializer-%E7%B1%BB"><span class="nav-number">3.2.1.5.2.</span> <span class="nav-text">2&gt; DataSourceInitializer 类</span></a></li></ol></li></ol></li></ol></li></ol></li></ol></div>
      </section>
      <!--/noindex-->

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="TANGMONK-MEAT"
      src="https://s1.ax1x.com/2020/09/22/wOscW9.jpg">
  <p class="site-author-name" itemprop="name">TANGMONK-MEAT</p>
  <div class="site-description" itemprop="description">直到这一刻微笑着说话为止，我至少留下了一公升眼泪</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/blog/archives/">
        
          <span class="site-state-item-count">38</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/blog/categories/">
          
        <span class="site-state-item-count">17</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/blog/tags/">
          
        <span class="site-state-item-count">44</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/TANGMONK-MEAT" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;TANGMONK-MEAT" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:2950371251@qq.com" title="E-Mail → mailto:2950371251@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://gitee.com/TANGMONK-MEAT" title="Gitee → https:&#x2F;&#x2F;gitee.com&#x2F;TANGMONK-MEAT" rel="noopener" target="_blank"><i class="iconfont icongitee-fill-round fa-fw"></i>Gitee</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://www.leancloud.cn/" title="LeanCloud → https:&#x2F;&#x2F;www.leancloud.cn" rel="noopener" target="_blank"><i class="iconfont iconCloudupload fa-fw"></i>LeanCloud</a>
      </span>
  </div>
  <div class="cc-license animated" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh-CN" class="cc-opacity" rel="noopener" target="_blank"><img src="/blog/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>



      </section>
    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </header>

      
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

  <a href="https://github.com/TANGMONK-MEAT" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>

<noscript>
  <div id="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


      <div class="main-inner">
        

        <div class="content post posts-expand">
          

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://tangmonk-meat.gitee.io/blog/2021/03/19/springboot2.x%E6%95%B4%E5%90%88JDBC%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%BA%90%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="https://s1.ax1x.com/2020/09/22/wOscW9.jpg">
      <meta itemprop="name" content="TANGMONK-MEAT">
      <meta itemprop="description" content="直到这一刻微笑着说话为止，我至少留下了一公升眼泪">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="唐僧肉BLOG">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          SpringBoot2.x整合JDBC与数据源配置原理解析
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2021-03-19 21:16:54" itemprop="dateCreated datePublished" datetime="2021-03-19T21:16:54+08:00">2021-03-19</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2020-09-23 10:28:36" itemprop="dateModified" datetime="2020-09-23T10:28:36+08:00">2020-09-23</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/blog/categories/SpringBoot/" itemprop="url" rel="index"><span itemprop="name">SpringBoot</span></a>
                </span>
            </span>

          
            <span id="/blog/2021/03/19/springboot2.x%E6%95%B4%E5%90%88JDBC%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%BA%90%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/" class="post-meta-item leancloud_visitors" data-flag-title="SpringBoot2.x整合JDBC与数据源配置原理解析" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/blog/2021/03/19/springboot2.x%E6%95%B4%E5%90%88JDBC%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%BA%90%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/blog/2021/03/19/springboot2.x%E6%95%B4%E5%90%88JDBC%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%BA%90%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/" itemprop="commentCount"></span>
    </a>
  </span>
  
  <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>23k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>21 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="1-基本概念"><a href="#1-基本概念" class="headerlink" title="1 基本概念"></a>1 基本概念</h1><h2 id="1-1-JDBC"><a href="#1-1-JDBC" class="headerlink" title="1.1 JDBC"></a>1.1 JDBC</h2><p><strong>JDBC</strong> 的全称是Java数据库连接(Java Database Connectivity，简称JDBC),是Java语言中用来<strong>规范客户端程序如何来访问数据库的应用程序接口</strong>。</p>
<p>提供了诸如查询和更新数据库中数据的方法,JDBC也是Sun Microsystems的商标。我们通常说的<strong>JDBC是面向关系型数据库的</strong>。</p>
<a id="more"></a>

<p><strong>JDBC API</strong> 主要位于JDK中的<code>java.sql</code>包中（之后扩展的内容位于　javax.sql　包中），主要包括（这几个代表接口，需驱动程序提供者来具体实现）：</p>
<ul>
<li><p><code>DriverManager</code>：负责加载各种不同驱动程序（Driver），并根据不同的请求，向调用者返回相应的数据库连接（Connection）。</p>
</li>
<li><p><code>Driver</code>：驱动程序，会将自身加载到DriverManager中去，并处理相应的请求并返回相应的数据库连接（Connection）。</p>
</li>
<li><p><code>Connection</code>：数据库连接，负责与进行数据库间通讯，SQL执行以及事务处理都是在某个特定Connection环境中进行的。可以产生用以执行SQL的Statement。</p>
</li>
<li><p><code>Statement</code>：用以执行SQL查询和更新（针对静态SQL语句和单次执行）。</p>
</li>
<li><p><code>PreparedStatement</code>：用以执行包含动态参数的SQL查询和更新（在服务器端编译，允许重复执行以提高效率）。</p>
</li>
<li><p><code>CallableStatement</code>：用以调用数据库中的存储过程。</p>
</li>
<li><p><code>SQLException</code>：代表在数据库连接的建立和关闭和SQL语句的执行过程中发生了例外情况（即错误）。</p>
</li>
</ul>
<h2 id="1-2-数据源"><a href="#1-2-数据源" class="headerlink" title="1.2 数据源"></a>1.2 数据源</h2><p>在<code>java.sql</code>中并没有数据源（<strong>Data Source</strong>）的概念。这是由于在java.sql中包含的是JDBC内核API．</p>
<p>另外还有个<code>javax.sql</code>包，其中包含了JDBC标准的扩展API。而关于数据源（<strong>Data Source</strong>）的定义，就在javax.sql这个扩展包中。</p>
<p>实际上，在JDBC内核API的实现下，就已经可以实现对数据库的访问了，那么我们为什么还需要数据源呢？主要出于以下几个目的：</p>
<ul>
<li><p>封装关于数据库访问的各种参数，实现统一管理</p>
</li>
<li><p>通过对数据库的连接池管理，节省开销并提高效率</p>
</li>
</ul>
<p>在Java的生态环境中，已经有非常多优秀的开源数据源，比如：DBCP、C3P0、Druid、<strong>HikariCP</strong>(重点)等。</p>
<p><strong>在Spring Boot 2.x中，对数据源的选择，采用了目前性能最佳的<a target="_blank" rel="noopener" href="https://github.com/brettwooldridge/HikariCP">HikariCP</a>。这个就是　Spring Boot２.x 中的默认数据源配置。</strong></p>
<hr>
<h1 id="2-整合步骤"><a href="#2-整合步骤" class="headerlink" title="2 整合步骤"></a>2 整合步骤</h1><blockquote>
<p>对于数据访问层，无论是SQL还是NOSQL，Spring Boot默认采用整合<code>Spring Data</code>的方式进行统一处理，添加大量自动配置，屏蔽了很多设置。<br>引入各种xxxTemplate，xxxRepository来简化我们对数据访问层的操作。<br>对我们来说只需要进行简单的设置即可。</p>
</blockquote>
<p><strong>版本：</strong></p>
<p>SpringBoot(v2.3.2.RELEASE)</p>
<p><strong>注意：</strong>　</p>
<p>引入的组件，如果在父POM全局管理spring-boot依赖版本的前提下，只需要在项目pom文件的dependencies元素直接引入．</p>
<p>创建工程时，只需添加SQL模块的<code>jdbc API</code>、<code>MySQL Driver</code>即可，在配置文件中配置数据源信息，就可以获取到数据库的连接。</p>
<p>并且数据源默认使用的是<code>HiKari</code>。数据源信息是从<code>DataSourceProperties</code>获取的</p>
<h2 id="2-1-引入JDBC的Starter"><a href="#2-1-引入JDBC的Starter" class="headerlink" title="2.1 引入JDBC的Starter"></a>2.1 引入JDBC的Starter</h2><blockquote>
<p>spring-boot-starter-jdbc</p>
</blockquote>
<p><code>spring-boot-starter-jdbc</code>提供了数据源配置、事务管理、数据访问等等功能，而对于不同类型的数据库，需要提供不同的驱动实现，才能更加简单地通过驱动实现根据连接URL、用户口令等属性直接连接数据库（或者说获取数据库的连接），因此<strong>对于不同类型的数据库，需要引入不同的驱动包依赖</strong>。</p>
<p>pom.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--引入　SpringBoot 的 jdbc模块--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-jdbc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line">      <span class="comment">&lt;!-- 如果是使用log4j2，则要排除SpringBoot 默认的logback 日志框架--&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-logging<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p><img data-src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9zMS5heDF4LmNvbS8yMDIwLzA4LzA4L2E0WmJNOC5wbmc?x-oss-process=image/format,png" alt="a4ZbM8.png"></p>
<p>spring-boot-starter-jdbc模块（间接引入spring-core、spring-beans、spring-tx）、spring-boot-starter和HikariCP三个依赖。</p>
<p>引入spring-boot-starter-jdbc模块后，SpringBoot是自动配置了<code>jdbcTamplate</code>的，可以使用<code>jdbcTamplate</code>来操作数据查询。</p>
<h2 id="2-2-引入连接数据库的驱动"><a href="#2-2-引入连接数据库的驱动" class="headerlink" title="2.2 引入连接数据库的驱动"></a>2.2 引入连接数据库的驱动</h2><blockquote>
<p>mysql-connector-java</p>
</blockquote>
<p>对于MySQL而言，需要引入<code>mysql-connector-java</code>，</p>
<p>其中有数据库抽象驱动接口<code>java.sql.Driver</code>的实现类：</p>
<ul>
<li>对于mysql-connector-java而言，常用的实现是<code>com.mysql.cj.jdbc.Driver</code>（MySQL8.x版本）。</li>
</ul>
<p>pom.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--mysql8 驱动--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="2-3-配置数据源-默认HikariCP"><a href="#2-3-配置数据源-默认HikariCP" class="headerlink" title="2.3 配置数据源(默认HikariCP)"></a>2.3 配置数据源(默认HikariCP)</h2><p><a target="_blank" rel="noopener" href="http://brettwooldridge.github.io/HikariCP/">HikariCP官网</a></p>
<blockquote>
<p>springboot2.x默认是用<code>com.zaxxer.hikari.HikariDataSource</code>作为数据源。<br>2.0以下默认采用的是<code>org.apache.tomcat.jdbc.pool.DataSource</code>作为数据源。</p>
</blockquote>
<blockquote>
<p>springboot2.x的<strong>spring-boot-starter-jdbc模块</strong> 默认使用<code>HikariCP</code>作为数据库的连接池</p>
</blockquote>
<blockquote>
<p><code>HikariCP</code>，也就是Hikari Connection Pool，Hikari连接池。HikariCP的作者是日本人，而Hikari是日语，意义和light相近，也就是”光”。Simplicity is prerequisite for reliability（简单是可靠的先决条件）是HikariCP的设计理念，他是一款代码精悍的高性能连接池框架，被Spring项目选中作为内建默认连接池，值得信赖。</p>
</blockquote>
<blockquote>
<p>由于Spring Boot的自动化配置机制，大部分对于数据源的配置都可以通过配置参数的方式去改变。</p>
</blockquote>
<p>在Spring Boot自动化配置中，对于数据源的配置可以分为两类：</p>
<ul>
<li><p><strong>通用配置</strong>：　以<code>spring.datasource.*</code>的形式存在，主要是对一些即使使用不同数据源也都需要配置的一些常规内容。</p>
<p>比如：数据库链接地址、用户名、密码等。通常就这些配置：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># 注意MySQL8.x需要指定服务时区属性</span><br><span class="line">spring.datasource.url&#x3D;jdbc:mysql:&#x2F;&#x2F;localhost:3306&#x2F;test?serverTimezone&#x3D;Asia&#x2F;Shanghai&amp;useUnicode&#x3D;true&amp;characterEncoding&#x3D;utf8&amp;useSSL&#x3D;true</span><br><span class="line">spring.datasource.username&#x3D;xxx</span><br><span class="line">spring.datasource.password&#x3D;xxx</span><br><span class="line"># 注意MySQL8.x的驱动</span><br><span class="line">spring.datasource.driver-class-name&#x3D;com.mysql.cj.jdbc.Driver</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>数据源连接池配置</strong>：以<code>spring.datasource.&lt;数据源名称&gt;.*</code>的形式存在。</p>
<p>比如：<code>Hikari</code> 的配置参数就是<code>spring.datasource.hikari.*</code>形式。</p>
<p>注意，需要指明数据源的类型:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">spring.datasource.type: com.zaxxer.hikari.HikariDataSource</span><br></pre></td></tr></table></figure>

<p>下面这个是我们最常用的几个配置项及对应说明：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># 连接池中允许的最大连接数。缺省值：10；推荐的公式：(cpu核心数*2+磁盘数)</span><br><span class="line">maximum-pool-size: 15</span><br><span class="line"># 一个连接idle状态的最大时长（毫秒），超时则被释放（retired），缺省:10分钟</span><br><span class="line">idle-timeout: 600000</span><br><span class="line"># 等待连接池分配连接的最大时长（毫秒），超过这个时长还没可用的连接则发生SQLException， 缺省:30秒</span><br><span class="line">connection-timeout: 30000</span><br><span class="line"># 连接只读数据库时配置为true， 保证安全</span><br><span class="line">read-only: false</span><br><span class="line"># 一个连接的生命时长（毫秒），超时而且没被使用则被释放（retired），缺省:30分钟，建议设置比数据库超时时长少30秒，参考MySQL wait_timeout参数（show variables like &#39;%timeout%&#39;;）</span><br><span class="line">max-lifetime: 1800000</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h3 id="2-3-1-数据源完整配置项表"><a href="#2-3-1-数据源完整配置项表" class="headerlink" title="2.3.1 数据源完整配置项表"></a>2.3.1 数据源完整配置项表</h3><p>|name    |描述    |构造器默认值    |默认配置validate之后的值    |validate重置|<br>|:—:|:—-:|:—-:|:—-:|:—-:|:——-:|<br>|autoCommit|    自动提交从池中返回的连接|    TRUE|    TRUE|    –|<br>|connectionTimeout|    等待来自池的连接的最大毫秒数|    SECONDS.toMillis(30) = 30000|    30000|    如果小于250毫秒，则被重置回30秒|<br>|idleTimeout|    连接允许在池中闲置的最长时间|    MINUTES.toMillis(10) = 600000|    600000|    如果idleTimeout+1秒&gt;maxLifetime 且 maxLifetime&gt;0，则会被重置为0（代表永远不会退出）；如果idleTimeout!=0且小于10秒，则会被重置为10秒|<br>|maxLifetime    |池中连接最长生命周期    |MINUTES.toMillis(30) = 1800000    |1800000    |如果不等于0且小于30秒则会被重置回30分钟|<br>|connectionTestQuery    |如果您的驱动程序支持JDBC4，我们强烈建议您不要设置此属性|    null|    null|    –|<br>|minimumIdle    |池中维护的最小空闲连接数    |-1    |10    |minIdle&lt;0或者minIdle&gt;maxPoolSize,则被重置为maxPoolSize|<br>|maximumPoolSize    |池中最大连接数，包括闲置和使用中的连接|    -1|    10    |如果maxPoolSize小于1，则会被重置。当minIdle&lt;=0被重置为DEFAULT_POOL_SIZE则为10;如果minIdle&gt;0则重置为minIdle的值|<br>|metricRegistry    |该属性允许您指定一个 Codahale / Dropwizard MetricRegistry 的实例，供池使用以记录各种指标|    null    |null    |–|<br>|healthCheckRegistry    |该属性允许您指定池使用的Codahale / Dropwizard HealthCheckRegistry的实例来报告当前健康信息    |null    |null    |–|<br>|poolName    |连接池的用户定义名称，主要出现在日志记录和JMX管理控制台中以识别池和池配置|    null    |HikariPool-1|    –|<br>|initializationFailTimeout    |如果池无法成功初始化连接，则此属性控制池是否将 fail fast|    1|    1    |–|<br>|isolateInternalQueries|    是否在其自己的事务中隔离内部池查询，例如连接活动测试|    FALSE    |FALSE|    –|<br>|allowPoolSuspension    |控制池是否可以通过JMX暂停和恢复    |FALSE|    FALSE|    –|<br>|readOnly    |从池中获取的连接是否默认处于只读模式|    FALSE|    FALSE|    –|<br>|registerMbeans    |是否注册JMX管理Bean（MBeans）|    FALSE    |FALSE|    –|<br>|catalog|    |为支持 catalog 概念的数据库设置默认 catalog|    driver default|    null|    –|<br>|connectionInitSql    |该属性设置一个SQL语句，在将每个新连接创建后，将其添加到池中之前执行该语句。|    null|    null|    –|<br>|driverClassName|    HikariCP将尝试通过仅基于jdbcUrl的DriverManager解析驱动程序，但对于一些较旧的驱动程序，还必须指定driverClassName|    null|    null|    –|<br>|transactionIsolation|    控制从池返回的连接的默认事务隔离级别|    null    |null|    –|<br>|validationTimeout|    连接将被测试活动的最大时间量|    SECONDS.toMillis(5) = 5000|    5000|    如果小于250毫秒，则会被重置回5秒|<br>|leakDetectionThreshold    |记录消息之前连接可能离开池的时间量，表示可能的连接泄漏|    0    |0    |如果大于0且不是单元测试，则进一步判断：(leakDetectionThreshold &lt; SECONDS.toMillis(2) or (leakDetectionThreshold &gt; maxLifetime &amp;&amp; maxLifetime &gt; 0)，会被重置为0 . 即如果要生效则必须&gt;0，而且不能小于2秒，而且当maxLifetime &gt; 0时不能大于maxLifetime|<br>|dataSource    |这个属性允许你直接设置数据源的实例被池包装，而不是让HikariCP通过反射来构造它|    null|    null|    –|<br>|schema|    该属性为支持模式概念的数据库设置默认模式|    driver default|    null    |–|<br>|threadFactory    |此属性允许您设置将用于创建池使用的所有线程的java.util.concurrent.ThreadFactory的实例|    null|null|–|<br>|scheduledExecutor|    此属性允许您设置将用于各种内部计划任务的java.util.concurrent.ScheduledExecutorService实例|    null|    null|    –|</p>
<h3 id="2-3-2-使用其他数据源（Druid）"><a href="#2-3-2-使用其他数据源（Druid）" class="headerlink" title="2.3.2 使用其他数据源（Druid）"></a>2.3.2 使用其他数据源（Druid）</h3><p><a target="_blank" rel="noopener" href="https://github.com/alibaba/druid">Druid(github)</a><br><a target="_blank" rel="noopener" href="http://druid.io/">Druid官网</a><br><a target="_blank" rel="noopener" href="https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter">Druid Spring Boot Starter</a><br><a target="_blank" rel="noopener" href="https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98">Druid的中文说明</a></p>
<blockquote>
<p>要禁用默认的数据源，改成Durid提供的数据源, 引入Druid数据源需要额外添加依赖</p>
<p>Druid的最强大之处在于它有着强大的监控，可以监控我们发送到数据库的所有sql语句,<br>方便我们后期排插错误</p>
</blockquote>
<p>当我们需要使用其他数据库连接池时：</p>
<ul>
<li><p>排除默认的数据源</p>
</li>
<li><p>导入相关的jar包</p>
</li>
<li><p>配置数据源信息</p>
</li>
</ul>
<h4 id="（1）排除默认数据源"><a href="#（1）排除默认数据源" class="headerlink" title="（1）排除默认数据源"></a>（1）排除默认数据源</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--配置默认数据源 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-jdbc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 排除默认的 HikariCP 数据源 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.zaxxer<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>HikariCP<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="（2）引用-阿里巴巴的Druid数据源"><a href="#（2）引用-阿里巴巴的Druid数据源" class="headerlink" title="（2）引用　阿里巴巴的Druid数据源"></a>（2）引用　阿里巴巴的Druid数据源</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 引用阿里巴巴的druid数据源 --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>druid-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.23<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h4 id="（3）配置Druid数据源"><a href="#（3）配置Druid数据源" class="headerlink" title="（3）配置Druid数据源"></a>（3）配置Druid数据源</h4><p>Druid Spring Boot Starter 配置属性的名称完全遵照 Druid；</p>
<ul>
<li><p>我们可以通过 Spring Boot 配置文件(application.yml / application.properties)来配置Druid数据库连接池和监控，如果没有配置则使用默认值。<a target="_blank" rel="noopener" href="https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter">具体配置可以参考Druid Spring Boot Starter</a> </p>
</li>
<li><p><code>DruidDataSource</code> 内提供 setter方法 的可配置属性都将被支持。你可以<a target="_blank" rel="noopener" href="https://github.com/alibaba/druid/wiki">参考WIKI文档</a>或通过IDE输入提示来进行配置。配置文件的格式你可以选择<code>*.properties</code>或<code>*.yml</code>，效果是一样的，在配置较多的情况下推荐使用<code>*.yml</code>。</p>
</li>
<li><p>也可以自己写Druid的配置文件和@Configuration来配置；</p>
</li>
</ul>
<p>这里我是自己定制的Druid的配置文件，在<code>DruidDataSource</code>里面 <strong>配置监控中心</strong>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(&#123;DruidDataSource.class&#125;)</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean(&#123;DataSource.class&#125;)</span></span><br><span class="line"><span class="meta">@ConditionalOnProperty(</span></span><br><span class="line"><span class="meta">        name = &#123;&quot;spring.datasource.type&quot;&#125;,</span></span><br><span class="line"><span class="meta">        havingValue = &quot;com.alibaba.druid.pool.DruidDataSource&quot;</span></span><br><span class="line"><span class="meta">)</span></span><br><span class="line"><span class="meta">@PropertySource(value = &quot;classpath:druid.properties&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DruidConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 注册 Druid 数据源</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ConfigurationProperties(prefix = &quot;spring.datasource&quot;)</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> DataSource <span class="title">druidDataSource</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> DruidDataSource();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">     <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 配置 监控服务器</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 返回监控注册的servlet对象</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ServletRegistrationBean <span class="title">statViewServlet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// </span></span><br><span class="line">        ServletRegistrationBean servletRegistrationBean = <span class="keyword">new</span> ServletRegistrationBean(<span class="keyword">new</span> StatViewServlet(), <span class="string">&quot;/druid/*&quot;</span>);</span><br><span class="line">        <span class="comment">// 添加IP白名单</span></span><br><span class="line">        servletRegistrationBean.addInitParameter(<span class="string">&quot;allow&quot;</span>, <span class="string">&quot;127.0.0.1&quot;</span>);</span><br><span class="line">        <span class="comment">// 添加IP黑名单，当白名单和黑名单重复时，黑名单优先级更高</span></span><br><span class="line">        servletRegistrationBean.addInitParameter(<span class="string">&quot;deny&quot;</span>, <span class="string">&quot;127.0.0.1&quot;</span>);</span><br><span class="line">        <span class="comment">// 添加控制台管理用户</span></span><br><span class="line">        servletRegistrationBean.addInitParameter(<span class="string">&quot;loginUsername&quot;</span>, <span class="string">&quot;123&quot;</span>);</span><br><span class="line">        servletRegistrationBean.addInitParameter(<span class="string">&quot;loginPassword&quot;</span>, <span class="string">&quot;123&quot;</span>);</span><br><span class="line">        <span class="comment">// 是否能够重置数据</span></span><br><span class="line">        servletRegistrationBean.addInitParameter(<span class="string">&quot;resetEnable&quot;</span>, <span class="string">&quot;false&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> servletRegistrationBean;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 配置服务过滤器</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 返回过滤器配置对象</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> FilterRegistrationBean <span class="title">statFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        FilterRegistrationBean filterRegistrationBean = <span class="keyword">new</span> FilterRegistrationBean(<span class="keyword">new</span> WebStatFilter());</span><br><span class="line">        <span class="comment">// 添加过滤规则</span></span><br><span class="line">        filterRegistrationBean.addUrlPatterns(<span class="string">&quot;/*&quot;</span>);</span><br><span class="line">        <span class="comment">// 忽略过滤格式</span></span><br><span class="line">        filterRegistrationBean.addInitParameter(<span class="string">&quot;exclusions&quot;</span>, <span class="string">&quot;*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> filterRegistrationBean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>配置完后我们启动SpringBoot程序访问：</p>
<p><a target="_blank" rel="noopener" href="http://localhost:8080/druid/">http://localhost:8080/druid/</a> 就可以来到我们的<strong>登录页面</strong>，登录之后，就是我们上面添加的<strong>控制台</strong>，我们可以在上面很好的看到运行状况。</p>
<hr>
<h1 id="3-数据源的自动配置原理（以hikari为例）"><a href="#3-数据源的自动配置原理（以hikari为例）" class="headerlink" title="3 数据源的自动配置原理（以hikari为例）"></a>3 数据源的自动配置原理（以hikari为例）</h1><h2 id="3-1-单元测试及其结果"><a href="#3-1-单元测试及其结果" class="headerlink" title="3.1 单元测试及其结果"></a>3.1 单元测试及其结果</h2><p><strong>1. 单元测试</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RunWith(SpringRunner.class)</span></span><br><span class="line"><span class="meta">@SpringBootTest</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SpringbootJdbcDemoApplicationTests</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Qualifier(&quot;dataSource&quot;)</span></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> DataSource dataSource;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">contextLoads</span><span class="params">()</span> <span class="keyword">throws</span> SQLException </span>&#123;</span><br><span class="line">        Connection connection = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 获取连接</span></span><br><span class="line">            connection = dataSource.getConnection();</span><br><span class="line">            <span class="comment">// 打印 数据源</span></span><br><span class="line">            System.out.println(<span class="string">&quot;【dataSourceClass=】&quot;</span> + dataSource.getClass());</span><br><span class="line">            <span class="comment">// 打印 连接对象</span></span><br><span class="line">            System.out.println(<span class="string">&quot;【connectionClass=】&quot;</span> + connection.getClass());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (SQLException throwables) &#123;</span><br><span class="line">            throwables.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="comment">// 断言，连接不可以为空，才关闭连接</span></span><br><span class="line">            <span class="keyword">assert</span> connection != <span class="keyword">null</span>;</span><br><span class="line">            connection.close();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>2. 运行结果</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">14:49:28.092 [main] INFO  com.springboot.template.SpringbootJdbcDemoApplicationTests - Started SpringbootJdbcDemoApplicationTests in 1.818 seconds (JVM running for 3.051)</span><br><span class="line"></span><br><span class="line">14:49:28.248 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...</span><br><span class="line">14:49:29.375 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.</span><br><span class="line"></span><br><span class="line">&#x2F;&#x2F; 单元测试的打印结果</span><br><span class="line">【dataSourceClass&#x3D;】class com.zaxxer.hikari.HikariDataSource</span><br><span class="line">【connectionClass&#x3D;】class com.zaxxer.hikari.pool.HikariProxyConnection</span><br><span class="line"></span><br><span class="line">14:49:29.400 [SpringContextShutdownHook] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...</span><br><span class="line">14:49:29.407 [SpringContextShutdownHook] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.</span><br><span class="line">14:49:29.407 [SpringContextShutdownHook] INFO  org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Shutting down ExecutorService &#39;applicationTaskExecutor&#39;</span><br><span class="line">Disconnected from the target VM, address: &#39;127.0.0.1:57273&#39;, transport: &#39;socket&#39;</span><br></pre></td></tr></table></figure>

<p>可以看到， springboot2.x 默认数据源使用的是<code>hikariDatasorece</code>。</p>
<h2 id="3-2-原理解析"><a href="#3-2-原理解析" class="headerlink" title="3.2 原理解析"></a>3.2 原理解析</h2><blockquote>
<p>相关配置类，都可以在<code>org.springframework.boot.autoconfigure.jdbc</code>下找到</p>
<p>数据源的相关属性配置都是在 <code>DataSourceProperties</code> 中；<br>实际的数据源导入配置都在<code>DataSourceConfiguration</code>中；<br>实际的数据源的自动配置都在 <code>DataSourceAutoConfiguration</code> 中。</p>
</blockquote>
<h3 id="3-2-1-数据源的导入配置"><a href="#3-2-1-数据源的导入配置" class="headerlink" title="3.2.1 数据源的导入配置"></a>3.2.1 数据源的导入配置</h3><blockquote>
<p>org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration</p>
</blockquote>
<p>SpringBoot支持的数据源，有如下几个：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;&#x2F; SpringBoot默认支持的三个数据源</span><br><span class="line">org.apache.commons.dbcp2.BasicDataSource： dbcp2的数据源</span><br><span class="line">com.zaxxer.hikari.HikariDataSource： hikari的数据源（默认的）</span><br><span class="line">org.apache.tomcat.jdbc.pool.DataSource： tomcat的数据源</span><br><span class="line">&#x2F;&#x2F; 使用其他的数据库连接池：例如Druid</span><br><span class="line">Generic： 其他的数据源</span><br></pre></td></tr></table></figure>

<h4 id="（1）hikari的数据源的配置原理"><a href="#（1）hikari的数据源的配置原理" class="headerlink" title="（1）hikari的数据源的配置原理"></a>（1）hikari的数据源的配置原理</h4><blockquote>
<p>org.springframework.boot.jdbc.DataSourceConfiguration</p>
</blockquote>
<p>根据项目导入的依赖和配置文件配置的限定，选择性的将SpringBoot支持的指定数据源，注册到Spring的IOC容器中。</p>
<p><strong>1&gt; 静态成员内部类 <code>Hikari</code></strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">DataSourceConfiguration</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">// 配置类，以下几个注解同时成立，@Configuration才生效</span></span><br><span class="line">    <span class="meta">@Configuration(</span></span><br><span class="line"><span class="meta">        proxyBeanMethods = false</span></span><br><span class="line"><span class="meta">    )</span></span><br><span class="line">    <span class="comment">// 在当前类路径下必须存在 HikariDataSource.class， 配置类才被注册</span></span><br><span class="line">    <span class="meta">@ConditionalOnClass(&#123;HikariDataSource.class&#125;)</span></span><br><span class="line">    <span class="comment">// 仅在该注解规定的类DataSource不存在于 spring容器中时，配置类才被注册，避免生成多个dataSource</span></span><br><span class="line">    <span class="meta">@ConditionalOnMissingBean(&#123;DataSource.class&#125;)</span></span><br><span class="line">    <span class="comment">// 控制配置类是否应该注册,</span></span><br><span class="line">    <span class="comment">// 通过其两个属性name以及havingValue来实现的，其中name用来从application.properties中读取某个属性值。</span></span><br><span class="line">    <span class="comment">// 如果该值为空，则返回false;</span></span><br><span class="line">    <span class="comment">// 如果值不为空，则将该值与havingValue指定的值进行比较，如果一样则返回true;否则返回false。</span></span><br><span class="line">    <span class="comment">// 如果返回值为false，则该configuration不生效；为true则生效。</span></span><br><span class="line">    <span class="meta">@ConditionalOnProperty(</span></span><br><span class="line"><span class="meta">        name = &#123;&quot;spring.datasource.type&quot;&#125;,</span></span><br><span class="line"><span class="meta">        havingValue = &quot;com.zaxxer.hikari.HikariDataSource&quot;,</span></span><br><span class="line"><span class="meta">        matchIfMissing = true</span></span><br><span class="line"><span class="meta">    )</span></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Hikari</span> </span>&#123;</span><br><span class="line">        Hikari() &#123;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="meta">@ConfigurationProperties(</span></span><br><span class="line"><span class="meta">            // 注入配置文件的属性配置，如初始连接数，最大最小等的前缀</span></span><br><span class="line"><span class="meta">            prefix = &quot;spring.datasource.hikari&quot;</span></span><br><span class="line"><span class="meta">        )</span></span><br><span class="line">        <span class="function">HikariDataSource <span class="title">dataSource</span><span class="params">(DataSourceProperties properties)</span> </span>&#123;</span><br><span class="line">            <span class="comment">// 创建 HikariDataSource ，绑定 相关属性信息 </span></span><br><span class="line">            HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);</span><br><span class="line">            <span class="keyword">if</span> (StringUtils.hasText(properties.getName())) &#123;</span><br><span class="line">                <span class="comment">// 设置连接池（数据源） 名称</span></span><br><span class="line">                dataSource.setPoolName(properties.getName());</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> dataSource;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">static</span> &lt;T&gt; <span class="function">T <span class="title">createDataSource</span><span class="params">(DataSourceProperties properties, Class&lt;? extends DataSource&gt; type)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 创建一个DataSourceBuilder对象，使用DataSourceBuilder创建数据源，利用反射创建指定type的数据源，并且绑定相关属性</span></span><br><span class="line">        <span class="comment">// 返回创建好的数据源</span></span><br><span class="line">        <span class="keyword">return</span> properties.initializeDataSourceBuilder().type(type).build();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//  略</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>2&gt; HikariDataSource (Hikari 数据源）</strong></p>
<blockquote>
<p>org.springframework.boot.jdbc.HikariDataSource</p>
</blockquote>
<p>实现了 <code>HikariConfig</code> 接口，这个就扣主要都是  Hikari 数据源的 配置信息；</p>
<p>继承 <code>javax.sql.DataSource</code> ，重写了 getConnection / setConnetion方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HikariDataSource</span> <span class="keyword">extends</span> <span class="title">HikariConfig</span> <span class="keyword">implements</span> <span class="title">DataSource</span>, <span class="title">Closeable</span> </span>&#123;</span><br><span class="line"> 	</span><br><span class="line"> 	<span class="keyword">private</span> <span class="keyword">final</span> AtomicBoolean isShutdown = <span class="keyword">new</span> AtomicBoolean();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> HikariPool fastPathPool;</span><br><span class="line">    <span class="comment">// Hikari 连接池，数据库连接由连接池提供</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> HikariPool pool;</span><br><span class="line"> 	<span class="comment">// setter、getter 等略</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看出，Hikari数据源的配置信息主要从两个类中读取：</p>
<ul>
<li><p>一个是<code>org.springframework.boot.autoconfigure.jdbc.DataSourceProperties</code>，</p>
</li>
<li><p>另一个则是本类HikariDataSource的父类<code>com.zaxxer.hikari.HikariConfig</code>。</p>
</li>
</ul>
<h4 id="（2）-数据源构建器（DataSourceBuilder）"><a href="#（2）-数据源构建器（DataSourceBuilder）" class="headerlink" title="（2） 数据源构建器（DataSourceBuilder）"></a>（2） 数据源构建器（DataSourceBuilder）</h4><blockquote>
<p>org.springframework.boot.jdbc.DataSourceBuilder</p>
</blockquote>
<p>上述使用到数据源构建器（DataSourceBuilder）类，创建 DataSource  </p>
<p>其中的<code>build</code>方法，利用反射创建指定type的数据源，并且绑定相关属性，返回一个<code>DataSource</code>对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 这里的 泛型T 就是 HikariDataSource</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">DataSourceBuilder</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">DataSource</span>&gt; </span>&#123;</span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line">    <span class="comment">// SpringBoot 支持的数据源 type</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] DATA_SOURCE_TYPE_NAMES = </span><br><span class="line">                <span class="keyword">new</span> String[]&#123;<span class="string">&quot;com.zaxxer.hikari.HikariDataSource&quot;</span>, </span><br><span class="line">                <span class="string">&quot;org.apache.tomcat.jdbc.pool.DataSource&quot;</span>, </span><br><span class="line">                <span class="string">&quot;org.apache.commons.dbcp2.BasicDataSource&quot;</span>&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">build</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 获取 HikariDataSource 的Class 对象</span></span><br><span class="line">        Class&lt;? extends DataSource&gt; type = <span class="keyword">this</span>.getType();</span><br><span class="line">        <span class="comment">// 利用反射，获取指定类型的数据源</span></span><br><span class="line">        DataSource result = (DataSource)BeanUtils.instantiateClass(type);</span><br><span class="line">        <span class="comment">// 设置连接数据库驱的动全类名，用于绑定到数据源</span></span><br><span class="line">        <span class="keyword">this</span>.maybeGetDriverClassName();</span><br><span class="line">        <span class="comment">// 绑定相关属性到 数据源</span></span><br><span class="line">        <span class="comment">// 相关属性就是 ：</span></span><br><span class="line">        <span class="comment">// username、password、url、driverClassName</span></span><br><span class="line">        <span class="keyword">this</span>.bind(result);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="（3）-hikari数据源的自动配置"><a href="#（3）-hikari数据源的自动配置" class="headerlink" title="（3） hikari数据源的自动配置"></a>（3） hikari数据源的自动配置</h4><blockquote>
<p>org.springframework.boot.jdbc.DataSourceAutoConfiguration</p>
</blockquote>
<p><code>DataSourceAutoConfiguration</code>是springboot加载数据源的核心配置类；</p>
<p>Spring Boot启动后会调用它，配置数据源。</p>
<p>DataSourceAutoConfiguration中有两个重要的嵌套类： </p>
<ul>
<li><p><code>EmbeddedDatabaseConfiguration</code>： 配置Spring Boot的嵌入示DataSource。除了Maven中加入相应的Driver，可以不做其他额外配置就能使用。从EmbeddedDatabaseType类可以看出，Spring Boot的内嵌DataSource支持 HSQL，H2，DERBY 这三种数据库。</p>
</li>
<li><p><code>PooledDataSourceConfiguration</code> ： 配置Spring Boot默认支持的一些DataSource。从<code>org.springframework.boot.jdbc.DataSourceBuilder</code>中可以看出，Spring Boot（2.x）只支持<code>com.zaxxer.hikari.HikariDataSource</code>，<code>org.apache.tomcat.jdbc.pool.DataSource</code>，<code>org.apache.commons.dbcp2.BasicDataSource</code>。</p>
</li>
</ul>
<p>以上两个配置类都会调用<code>ConfigurationClassParser</code>类的<code>processConfigurationClass</code>方法来处理</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 数据源的自动配置类</span></span><br><span class="line"><span class="meta">@Configuration(</span></span><br><span class="line"><span class="meta">    proxyBeanMethods = false</span></span><br><span class="line"><span class="meta">)</span></span><br><span class="line"><span class="comment">// 在当前类路径下存在DataSource.class,EmbeddedDatabaseType.class 时,这个配置类才注入到IOC容器</span></span><br><span class="line"><span class="meta">@ConditionalOnClass(&#123;DataSource.class, EmbeddedDatabaseType.class&#125;)</span></span><br><span class="line"><span class="comment">// 仅在该注解规定的类ConnectionFactory不存在于 spring容器中时，配置类才被注册</span></span><br><span class="line"><span class="meta">@ConditionalOnMissingBean(</span></span><br><span class="line"><span class="meta">    type = &#123;&quot;io.r2dbc.spi.ConnectionFactory&quot;&#125;</span></span><br><span class="line"><span class="meta">)</span></span><br><span class="line"><span class="comment">// 把 @ConfigurationProperties 注解的  DataSourceProperties类，注入到IOC容器</span></span><br><span class="line"><span class="comment">// 这就是自动配置的主要原因之一</span></span><br><span class="line"><span class="meta">@EnableConfigurationProperties(&#123;DataSourceProperties.class&#125;)</span></span><br><span class="line"><span class="comment">// 在运用的时候,获取该注解标识的类，注入到IOC容器</span></span><br><span class="line"><span class="comment">// DataSourcePoolMetadataProvidersConfiguration.class  自动装配每个数据源的元数据</span></span><br><span class="line"><span class="comment">// DataSourceInitializationConfiguration.class         数据源的初始化配置,</span></span><br><span class="line"><span class="meta">@Import(&#123;DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DataSourceAutoConfiguration</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 这里就使用到了上述的 DataSourceConfiguration抽象类，注入数据源（内部静态类）到IOC容器</span></span><br><span class="line">    <span class="comment">// 数据源导入的配置类</span></span><br><span class="line">    <span class="meta">@Configuration(</span></span><br><span class="line"><span class="meta">        proxyBeanMethods = false</span></span><br><span class="line"><span class="meta">    )</span></span><br><span class="line">    <span class="comment">// 配置有spring.datasource.type并且其值不是false 时生效,</span></span><br><span class="line">    <span class="comment">// 如果在当前类路径下存在: </span></span><br><span class="line">        <span class="comment">// org.apache.tomcat.jdbc.pool.DataSource</span></span><br><span class="line">        <span class="comment">// com.zaxxer.hikari.HikariDataSource</span></span><br><span class="line">        <span class="comment">// org.apache.commons.dbcp.BasicDataSource</span></span><br><span class="line">        <span class="comment">// org.apache.commons.dbcp2.BasicDataSource</span></span><br><span class="line">    <span class="comment">// 任意一个时,这个配置类才可以注入到IOC容器</span></span><br><span class="line">    <span class="meta">@Conditional(&#123;DataSourceAutoConfiguration.PooledDataSourceCondition.class&#125;)</span></span><br><span class="line">    <span class="comment">// IOC容器中不存在DataSource,XADataSource类型的bean时，这个配置类才可以注入到IOC容器</span></span><br><span class="line">    <span class="meta">@ConditionalOnMissingBean(&#123;DataSource.class, XADataSource.class&#125;)</span></span><br><span class="line">    <span class="comment">// 在运用的时候,将DataSourceConfiguration配置类中，符合条件的数据源，注入到IOC容器</span></span><br><span class="line">    <span class="comment">// 就是根据条件限制，依次导入Tomcat,Hikari,Dbcp, Dbcp2的配置</span></span><br><span class="line">    <span class="comment">// 如果没有，就检查有没有 Generic.class 其他的数据源</span></span><br><span class="line">    <span class="comment">// 还没有，就是使用内嵌的数据源</span></span><br><span class="line">    <span class="meta">@Import(&#123;Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class&#125;)</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">PooledDataSourceConfiguration</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="title">PooledDataSourceConfiguration</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="（4）使用其他数据源"><a href="#（4）使用其他数据源" class="headerlink" title="（4）使用其他数据源"></a>（4）使用其他数据源</h4><blockquote>
<p>org.springframework.boot.jdbc.DataSourceConfiguration</p>
</blockquote>
<p>可以使用 <code>spring.datasource.type</code> 指定自定义的数据源类型，值要使用数据源全类名。</p>
<p>默认情况下，它是从类路径自动检测的，源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">DataSourceConfiguration</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Configuration(</span></span><br><span class="line"><span class="meta">        proxyBeanMethods = false</span></span><br><span class="line"><span class="meta">    )</span></span><br><span class="line">    <span class="meta">@ConditionalOnMissingBean(&#123;DataSource.class&#125;)</span></span><br><span class="line">    <span class="meta">@ConditionalOnProperty(</span></span><br><span class="line"><span class="meta">        name = &#123;&quot;spring.datasource.type&quot;&#125;</span></span><br><span class="line"><span class="meta">    )</span></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Generic</span> </span>&#123;</span><br><span class="line">        Generic() &#123;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Bean</span></span><br><span class="line">        <span class="function">DataSource <span class="title">dataSource</span><span class="params">(DataSourceProperties properties)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> properties.initializeDataSourceBuilder().build();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看到，只要配置文件中，只配置了其他数据源，导入了其他数据源的依赖，那么，这个其他数据源就会被生成使用，转而会生成我们配置使用的数据源。</p>
<p>SpringBoot默认使用的数据源Hikari，因为不满足限定条件，而不会生成使用。</p>
<h4 id="（5）数据源的初始化"><a href="#（5）数据源的初始化" class="headerlink" title="（5）数据源的初始化"></a>（5）数据源的初始化</h4><blockquote>
<p>org.springframework.boot.autoconfigure.jdbc.DataSourceInitializationConfiguration</p>
</blockquote>
<p>这个类，在<code>DataSourceConfiguration</code>中，被注入到IOC容器;</p>
<p>主要作用是，数据源的初始化配置。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(</span></span><br><span class="line"><span class="meta">    proxyBeanMethods = false</span></span><br><span class="line"><span class="meta">)</span></span><br><span class="line"><span class="comment">// 运行时，注入这些标注的类</span></span><br><span class="line"><span class="meta">@Import(&#123;DataSourceInitializerInvoker.class, DataSourceInitializationConfiguration.Registrar.class&#125;)</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DataSourceInitializationConfiguration</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line">    <span class="comment">// 这个内部类</span></span><br><span class="line">    <span class="comment">// 主要是给 数据源bean，注册后置处理器</span></span><br><span class="line">    <span class="comment">// dataSourceInitializerPostProcessor</span></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Registrar</span> <span class="keyword">implements</span> <span class="title">ImportBeanDefinitionRegistrar</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String BEAN_NAME = <span class="string">&quot;dataSourceInitializerPostProcessor&quot;</span>;</span><br><span class="line"></span><br><span class="line">        Registrar() &#123;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerBeanDefinitions</span><span class="params">(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (!registry.containsBeanDefinition(<span class="string">&quot;dataSourceInitializerPostProcessor&quot;</span>)) &#123;</span><br><span class="line">                GenericBeanDefinition beanDefinition = <span class="keyword">new</span> GenericBeanDefinition();</span><br><span class="line">                beanDefinition.setBeanClass(DataSourceInitializerPostProcessor.class);</span><br><span class="line">                beanDefinition.setRole(<span class="number">2</span>);</span><br><span class="line">                beanDefinition.setSynthetic(<span class="keyword">true</span>);</span><br><span class="line">                registry.registerBeanDefinition(<span class="string">&quot;dataSourceInitializerPostProcessor&quot;</span>, beanDefinition);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="1-gt-DataSourceInitializerInvoke类"><a href="#1-gt-DataSourceInitializerInvoke类" class="headerlink" title="1&gt; DataSourceInitializerInvoke类"></a>1&gt; <code>DataSourceInitializerInvoke</code>类</h5><blockquote>
<p>org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoke</p>
</blockquote>
<p><code>DataSourceInitializerInvoke</code>,实现了ApplicationListener接口，实际上就是一个 监听器（ApplicationListener）；</p>
<p>这里它监听的是 <code>DataSourceSchemaCreatedEvent</code> 事件，就是建表的事件。</p>
<p><strong>作用:</strong>   </p>
<ul>
<li><p>初始化的时候帮我们运行schene-*文件(建表)，和 data-*（数据）；  </p>
</li>
<li><p><code>afterPropertiesSet</code>方法，初始化bean的时候执行，可以针对某个具体的bean进行配置</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DataSourceInitializerInvoker</span> <span class="keyword">implements</span> <span class="title">ApplicationListener</span>&lt;<span class="title">DataSourceSchemaCreatedEvent</span>&gt;, <span class="title">InitializingBean</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">afterPropertiesSet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 从容器中拿到数据源对象初始化器</span></span><br><span class="line">        DataSourceInitializer initializer = <span class="keyword">this</span>.getDataSourceInitializer();</span><br><span class="line">        <span class="keyword">if</span> (initializer != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="comment">// createSchema()-&gt;runScripts()，运行建表语句</span></span><br><span class="line">            <span class="keyword">boolean</span> schemaCreated = <span class="keyword">this</span>.dataSourceInitializer.createSchema();</span><br><span class="line">            <span class="comment">// 若建表语句创建成功</span></span><br><span class="line">            <span class="keyword">if</span> (schemaCreated) &#123;</span><br><span class="line">                <span class="comment">// initialize()-&gt;initSchema(),运行插入数据的语句</span></span><br><span class="line">                <span class="keyword">this</span>.initialize(initializer);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// DataSourceSchemaCreatedEvent 发生时，触发此方法</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onApplicationEvent</span><span class="params">(DataSourceSchemaCreatedEvent event)</span> </span>&#123;</span><br><span class="line">        DataSourceInitializer initializer = <span class="keyword">this</span>.getDataSourceInitializer();</span><br><span class="line">        <span class="keyword">if</span> (!<span class="keyword">this</span>.initialized &amp;&amp; initializer != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 运行插入数据的语句</span></span><br><span class="line">            initializer.initSchema();</span><br><span class="line">            <span class="keyword">this</span>.initialized = <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="2-gt-DataSourceInitializer-类"><a href="#2-gt-DataSourceInitializer-类" class="headerlink" title="2&gt; DataSourceInitializer 类"></a>2&gt; <code>DataSourceInitializer</code> 类</h5><blockquote>
<p>org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer</p>
</blockquote>
<p>默认只需要在类路径下，将文件命名为:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># schema‐*.sql、data‐*.sql</span><br><span class="line"># 默认规则：schema.sql，schema‐all.sql；</span><br><span class="line"># 可以使用自定义位置：</span><br><span class="line">schema:</span><br><span class="line">    ‐ classpath:department.sql</span><br></pre></td></tr></table></figure>

<p>就可以在SpringBoot启动后，执行sql脚本，在数据库，建表，更新数据。</p>
<p>部分源码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DataSourceInitializer</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 建表</span></span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">createSchema</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        List&lt;Resource&gt; scripts = <span class="keyword">this</span>.getScripts(<span class="string">&quot;spring.datasource.schema&quot;</span>, <span class="keyword">this</span>.properties.getSchema(), <span class="string">&quot;schema&quot;</span>);</span><br><span class="line">        <span class="comment">// 这里要在 application.properties 配置文件中配置，才会执行类路径下的sql脚本</span></span><br><span class="line">        <span class="comment">// spring.datasource.initialization-mode: always </span></span><br><span class="line">        <span class="keyword">if</span> (!scripts.isEmpty()) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="keyword">this</span>.isEnabled()) &#123;</span><br><span class="line">                logger.debug(<span class="string">&quot;Initialization disabled (not running DDL scripts)&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            String username = <span class="keyword">this</span>.properties.getSchemaUsername();</span><br><span class="line">            String password = <span class="keyword">this</span>.properties.getSchemaPassword();</span><br><span class="line">            <span class="keyword">this</span>.runScripts(scripts, username, password);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> !scripts.isEmpty();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 更新数据</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">initSchema</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        List&lt;Resource&gt; scripts = <span class="keyword">this</span>.getScripts(<span class="string">&quot;spring.datasource.data&quot;</span>, <span class="keyword">this</span>.properties.getData(), <span class="string">&quot;data&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (!scripts.isEmpty()) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="keyword">this</span>.isEnabled()) &#123;</span><br><span class="line">                logger.debug(<span class="string">&quot;Initialization disabled (not running data scripts)&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            String username = <span class="keyword">this</span>.properties.getDataUsername();</span><br><span class="line">            String password = <span class="keyword">this</span>.properties.getDataPassword();</span><br><span class="line">            <span class="keyword">this</span>.runScripts(scripts, username, password);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取 sql 脚本在类路径下的 位置</span></span><br><span class="line">    <span class="comment">// 默认是 classpath:schema-all.sql 和 classpath:schema.sql</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> List&lt;Resource&gt; <span class="title">getScripts</span><span class="params">(String propertyName, List&lt;String&gt; resources, String fallback)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (resources != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>.getResources(propertyName, resources, <span class="keyword">true</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// platform 默认是 all</span></span><br><span class="line">            String platform = <span class="keyword">this</span>.properties.getPlatform();</span><br><span class="line">            List&lt;String&gt; fallbackResources = <span class="keyword">new</span> ArrayList();</span><br><span class="line">            <span class="comment">// fallback 默认是 schema</span></span><br><span class="line">            <span class="comment">// classpath:schema-all.sql</span></span><br><span class="line">            fallbackResources.add(<span class="string">&quot;classpath*:&quot;</span> + fallback + <span class="string">&quot;-&quot;</span> + platform + <span class="string">&quot;.sql&quot;</span>);</span><br><span class="line">            <span class="comment">// classpath:schema.sql</span></span><br><span class="line">            fallbackResources.add(<span class="string">&quot;classpath*:&quot;</span> + fallback + <span class="string">&quot;.sql&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>.getResources(propertyName, fallbackResources, <span class="keyword">false</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 略</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>看getScripts源码，它还会加载<strong>schema-${platform}.sql</strong>文件，或者<strong>data-${platform}.sql</strong>文件，其中platform就是spring.datasource.platform的值；当然，也可以自定义sql脚本的名称，不过，需要在类路径下，配置sql脚本的位置信息。</p>
<p><strong>SpringBoot2.x 使用sql文件初始化的一些注意事项：</strong></p>
<ul>
<li>Springboot启动成功后，<br>下次要将sql脚本内的建表语句注释，<br>不然会报错：数据库表已经存在，无法创建  </li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nested exception is java.sql.SQLSyntaxErrorException: Table &#39;admin&#39; already exists</span><br></pre></td></tr></table></figure>

<ul>
<li>在application配置文件加上<code>spring.datasource.initialization-mode=always</code>,否则不生效;</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">spring.datasource.initialization-mode  </span><br><span class="line">初始化模式（springboot2.0），其中有三个值，</span><br><span class="line">always : 为始终执行初始化，</span><br><span class="line">embedded : 只初始化内存数据库（默认值）,如h2等，</span><br><span class="line">never : 为不执行初始化</span><br></pre></td></tr></table></figure>

<ul>
<li><strong>sql脚本中尽量不要使用注释</strong>，否则会把紧跟的sql语句解释为注释，而不执行。</li>
</ul>
<p>因为SpringBoot在启动时，只有检测到<code>spring.datasource.initialization-mode=always</code>配置；</p>
<p>然后，再检测<code>spring.datasource.schema</code> / <code>spring.datasource.data</code>，且配置的sql脚本语句不为空，才会去执行sql脚本。</p>
<p><strong>application.yml</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">spring:</span><br><span class="line">  datasource:</span><br><span class="line">    platform: mysql # 数据库类型</span><br><span class="line">    initialization-mode: always</span><br><span class="line">    schema:</span><br><span class="line">      - classpath:sql&#x2F;user.sql</span><br><span class="line">    data:</span><br><span class="line">      - classpath:sql&#x2F;userData.sql </span><br></pre></td></tr></table></figure>

<p>参考</p>
<p><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-sql">SpringBoot官方文档#Working with SQL Databases</a></p>
<p><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-configure-a-datasource">SpringBoot官方文档#Data Access</a></p>
<p><a target="_blank" rel="noopener" href="https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter">SpringBoot官方文档#Starters</a></p>
<p><a target="_blank" rel="noopener" href="https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby">HikariCP官方文档</a></p>
<p><a target="_blank" rel="noopener" href="http://www.lanxinbase.com/?p=2482">Spring Boot默认HikariDataSource配置</a></p>
<p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/didispace/p/12291832.html">默认数据源Hikari的配置详解</a></p>
<p><a target="_blank" rel="noopener" href="https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter">具体配置参考Druid Spring Boot Starter</a> </p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/jatpen/article/details/102062797">springboot2.x整合JDBC与数据源配置原理解析</a></p>

    </div>

     <!-- 文章结束表示语-->
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>
      
    </div>

    
    
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>TANGMONK-MEAT
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://tangmonk-meat.gitee.io/blog/2021/03/19/springboot2.x%E6%95%B4%E5%90%88JDBC%E4%B8%8E%E6%95%B0%E6%8D%AE%E6%BA%90%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/" title="SpringBoot2.x整合JDBC与数据源配置原理解析">https://tangmonk-meat.gitee.io/blog/2021/03/19/springboot2.x整合JDBC与数据源配置原理解析/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh-CN" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">
          <div class="post-tags">
              <a href="/blog/tags/SpringBoot/" rel="tag"><i class="fa fa-tag"></i> SpringBoot</a>
              <a href="/blog/tags/Spring/" rel="tag"><i class="fa fa-tag"></i> Spring</a>
              <a href="/blog/tags/jdbc/" rel="tag"><i class="fa fa-tag"></i> jdbc</a>
              <a href="/blog/tags/%E6%BA%90%E7%A0%81/" rel="tag"><i class="fa fa-tag"></i> 源码</a>
              <a href="/blog/tags/HikariCP/" rel="tag"><i class="fa fa-tag"></i> HikariCP</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/blog/2021/03/19/%E4%BD%BF%E7%94%A8log4j2%E6%89%93%E5%8D%B0JdbcTemplate%E7%9A%84sql%E5%8F%8A%E5%85%B6%E5%8F%82%E6%95%B0/" rel="prev" title="使用log4j2打印JdbcTemplate的sql及其参数">
      <i class="fa fa-chevron-left"></i> 使用log4j2打印JdbcTemplate的sql及其参数
    </a></div>
      <div class="post-nav-item">
    <a href="/blog/2021/03/19/Linux%E7%BB%88%E7%AB%AF%E5%91%BD%E4%BB%A4%E6%A0%BC%E5%BC%8F/" rel="next" title="Linux终端命令格式">
      Linux终端命令格式 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



        </div>
        
    <div class="comments" id="valine-comments"></div>

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">TANGMONK-MEAT</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
      <span class="post-meta-item-text">站点总字数：</span>
    <span title="站点总字数">148k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span class="post-meta-item-text">站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">2:15</span>
</div>

<!--
-->

<!--<div>
<span id="busuanzi_container_site_pv">
    本站总访问量<span id="busuanzi_value_site_pv"></span>次
</span> 
 <span class="post-meta-divider">|</span> 
 <span class="post-meta-item-icon">
<span id="busuanzi_container_site_uv">
  本站访客数<span id="busuanzi_value_site_uv"></span>人次
</span>
</div> 

-->




        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/blog/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/lozad@1/dist/lozad.min.js"></script>

<script src="/blog/js/utils.js"></script>

<script src="/blog/js/motion.js"></script>


<script src="/blog/js/schemes/muse.js"></script>


<script src="/blog/js/next-boot.js"></script>


  
  <script>
    (function(){
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      bp.src = (curProtocol === 'https') ? 'https://zz.bdstatic.com/linksubmit/push.js' : 'http://push.zhanzhang.baidu.com/push.js';
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
    })();
  </script>




  
<script src="/blog/js/local-search.js"></script>













  

  


<script>
NexT.utils.loadComments('#valine-comments', () => {
  NexT.utils.getScript('//cdn.jsdelivr.net/npm/valine@1/dist/Valine.min.js', () => {
    new Valine(Object.assign({
      el  : '#valine-comments',
      path: location.pathname,
    }, {"enable":true,"appId":"dkMV7sEQR97E6CWI5jduGKf3-gzGzoHsz","appKey":"JQfXJ0ELtfNma5bdMQk0vgwX","placeholder":"ヾﾉ≧∀≦)o来啊，快活啊!","avatar":"mm","meta":["nick","mail"],"pageSize":10,"language":"zh-cn","visitor":true,"comment_count":true,"recordIP":true,"serverURLs":null,"enableQQ":false,"requiredFields":[]}
    ));
  }, window.Valine);
});
</script>

</body>
</html>
